using System;
using System.Collections.Generic;
using System.Text;
using Barrage;
using Barrage.Global;
using SlimDX;
using SlimDX.Direct3D9;
using Barrage.Global.Vertex;

namespace Barrage.GUI.Meshes
{
    /// <summary>
    /// Specifies the grow mode of the ProgressiveRectangle class
    /// </summary>
    public enum ProgressiveRectangleLayout{
        /// <summary>
        /// The ProgressiveRectangle will grow from left to right
        /// </summary>
        HorizontalLeftToRight,
        /// <summary>
        /// The ProgressiveRectangle will grow from right to left
        /// </summary>
        HorizontalRightToLeft,
        /// <summary>
        /// The ProgressiveRectangle will grow from bottom to top
        /// </summary>
        VerticalDownToUp,
        /// <summary>
        /// The ProgressiveRectangle will grow from top to bottom
        /// </summary>
        VerticalUpToDown
    }
    /// <summary>
    /// ProgressiveRectangle is a rectangle with a progress parameter telling its length. Useful for gauges and progress bars.
    /// </summary>
    public class ProgressiveRectangle : Barrage.Meshes.GuiMesh
    {
        // Left-Top-Right-Bottom
        private float progress;

        private ProgressiveRectangleLayout layout = ProgressiveRectangleLayout.HorizontalLeftToRight;

        /// <summary>
        /// Grow mode of the rectangle
        /// </summary>
        public ProgressiveRectangleLayout Layout{get{return layout;}set{layout=value; dirty=true;}}


        private bool dirty = false;
        private Vector2 size;

        /// <summary>
        /// Rectangle progress, usually ranges from 0 to 1
        /// </summary>
        public float Progress { get { return progress; } set { progress = value; dirty = true; } }
        /// <summary>
        /// Rectangle size when progress is 1
        /// </summary>
        public Vector2 Size { get { return size; } set { size = value; dirty = true; } }


        private VertexBuffer rectangleBuffer = null;

        private void initializeBuffer()
        {
            rectangleBuffer = new VertexBuffer(Engine.Device, VertexPositionUV.SizeBytes * 4, Usage.WriteOnly | Usage.Dynamic, VertexPositionUV.Format, Pool.Default);
            fillBuffer();
        }

        private void fillBuffer()
        {
            DataStream stream = rectangleBuffer.Lock(0, 0, LockFlags.Discard);
            VertexPositionUV[] vertices = generateVertices();
            stream.WriteRange(vertices);
            rectangleBuffer.Unlock();

            dirty = false;

        }

        private VertexPositionUV[] generateVertices()
        {
            VertexPositionUV[] vertices = new VertexPositionUV[4];
            Vector2 halfSize = size / 2.0f;
            switch (layout){
                case ProgressiveRectangleLayout.HorizontalLeftToRight:
                    vertices[0].Position = new Vector3(-halfSize.X, halfSize.Y, 0); vertices[0].UV = new Vector2(0, 0);
                    vertices[1].Position = new Vector3(-halfSize.X + progress * size.X, halfSize.Y, 0); vertices[1].UV = new Vector2(progress, 0);
                    vertices[2].Position = new Vector3(-halfSize.X, -halfSize.Y, 0); vertices[2].UV = new Vector2(0, 1);
                    vertices[3].Position = new Vector3(-halfSize.X + progress*size.X, -halfSize.Y, 0); vertices[3].UV = new Vector2(progress, 1);
                    break;
                case ProgressiveRectangleLayout.HorizontalRightToLeft:
                    vertices[0].Position = new Vector3(halfSize.X - progress * size.X, halfSize.Y, 0); vertices[0].UV = new Vector2(1 - progress, 0);
                    vertices[1].Position = new Vector3(halfSize.X, halfSize.Y, 0); vertices[1].UV = new Vector2(1, 0);
                    vertices[2].Position = new Vector3(halfSize.X - progress * size.X, -0.5f, 0); vertices[2].UV = new Vector2(1 - progress, 1);
                    vertices[3].Position = new Vector3(halfSize.X, -halfSize.Y, 0); vertices[3].UV = new Vector2(1, 1);
                    break;
                case ProgressiveRectangleLayout.VerticalUpToDown:
                    vertices[0].Position = new Vector3(-halfSize.X, halfSize.Y, 0); vertices[0].UV = new Vector2(0, 0);
                    vertices[1].Position = new Vector3(halfSize.X, halfSize.Y, 0); vertices[1].UV = new Vector2(1, 0);
                    vertices[2].Position = new Vector3(-halfSize.X, halfSize.Y - progress * size.Y, 0); vertices[2].UV = new Vector2(0, progress);
                    vertices[3].Position = new Vector3(halfSize.X, halfSize.Y - progress * size.Y, 0); vertices[3].UV = new Vector2(1, progress);
                    break;
                case ProgressiveRectangleLayout.VerticalDownToUp:
                    vertices[0].Position = new Vector3(-halfSize.X, -halfSize.Y + progress * size.Y, 0); vertices[0].UV = new Vector2(0, 1 - progress);
                    vertices[1].Position = new Vector3(halfSize.X, -halfSize.Y + progress * size.Y, 0); vertices[1].UV = new Vector2(1, 1 - progress);
                    vertices[2].Position = new Vector3(-halfSize.X, -halfSize.Y, 0); vertices[2].UV = new Vector2(0, 1);
                    vertices[3].Position = new Vector3(halfSize.X, -halfSize.Y, 0); vertices[3].UV = new Vector2(1, 1);
                    break;
            }

            return vertices;

        }

        /// <summary>
        /// Inits the rectangle with a texture, initial size and grow mode
        /// </summary>
        /// <param name="texture">Texture to be used</param>
        /// <param name="size">Initial size</param>
        /// <param name="layout">Rectangle's grow mode</param>
        public ProgressiveRectangle(Texture texture, Vector2 size,ProgressiveRectangleLayout layout)
        {
            this.layout = layout;
            this.size = size;
            initializeBuffer();
            Materials[0].Texture = texture;

        }


        /// <summary>
        /// \internal Renders the mesh
        /// </summary>
        /// <param name="item">Item that is being rendered</param>
        public override void Render(Item item)
        {
            RenderStats.RenderCalls++;
            shader.BeginRender(item, materials[0]);
            //Engine.Device.SetRenderState(RenderState.CullMode, Cull.None);
            if (dirty) { fillBuffer(); }
            Engine.Device.VertexFormat = VertexPositionUV.Format;
            Engine.Device.SetStreamSource(0, rectangleBuffer, 0, VertexPositionUV.SizeBytes);
            int passNumber = shader.PassNumber(materials[0]);
            for (int j = 0; j < passNumber; j++)
            {
                shader.BeginPass(j);
                Engine.Device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
                shader.EndPass();
            }
            shader.EndRender();

        }

        /// <summary>
        /// \internal Free resources
        /// </summary>
        public override void Dispose()
        {
            rectangleBuffer.Dispose();
            rectangleBuffer = null;
            base.Dispose();
        }
    }
}
